package com.xiang.community.controller;

import com.github.pagehelper.PageInfo;
import com.xiang.community.annotation.LoginRequired;
import com.xiang.community.dto.MessageCountDTO;
import com.xiang.community.dto.PageResult;
import com.xiang.community.dto.ResultDTO;
import com.xiang.community.entity.Message;
import com.xiang.community.entity.User;
import com.xiang.community.enums.MessageStatusEnum;
import com.xiang.community.enums.MessageTypeEnum;
import com.xiang.community.enums.ResponseCodeEnum;
import com.xiang.community.exceptions.BusinessException;
import com.xiang.community.service.CommonService;
import com.xiang.community.service.MessageService;
import com.xiang.community.service.UserService;
import com.xiang.community.utils.CookieUtil;
import com.xiang.community.utils.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

import static com.xiang.community.constant.LoginConstant.MAP_KEY_TOKEN;
import static com.xiang.community.constant.RedisUtilConstant.PREFIX_USER_ID;

@RestController
@RequestMapping("/message")
public class MessageController {

    @Resource
    private MessageService messageService;
    @Resource
    private UserService userService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private HttpServletRequest request;
    @Resource
    private CommonService commonService;

    @GetMapping("/unreadConversationCount")
    @LoginRequired
    public ResultDTO getUnreadMessageCount() {
        String currentUserId = redisUtil.getValueFromString(PREFIX_USER_ID, CookieUtil.getValue(request, MAP_KEY_TOKEN));
        User user = commonService.getUserByUserId(currentUserId);
        Map<String, Object> map = new HashMap<>(1);
        int unreadConversationCount = messageService.getUnreadConversationCount(user.getId());
        int unreadSystemMessageCount = messageService.getUnreadSystemMessageCount(user.getId());
        map.put("unreadConversationCount", unreadSystemMessageCount + unreadConversationCount);
        return ResultDTO.builder().code(ResponseCodeEnum.SUCCESS.getCode()).data(map).build();
    }

    @GetMapping("/list/{messageType}")
    @LoginRequired
    public PageResult getMessageListWithPage(@RequestParam int pageNum, @RequestParam int pageSize, @PathVariable String messageType) {
        String currentUserId = redisUtil.getValueFromString(PREFIX_USER_ID, CookieUtil.getValue(request, MAP_KEY_TOKEN));
        User user = commonService.getUserByUserId(currentUserId);
        PageInfo<Message> pageInfo = null;
        if (MessageTypeEnum.SYSTEM.getType().equals(messageType)) {
            pageInfo = messageService.findSystemMessageWithPage(user.getId(), pageNum, pageSize);
        }

        if (MessageTypeEnum.MESSAGE.getType().equals(messageType)) {
            pageInfo = messageService.findConversationsWithPage(user.getId(), messageType, pageNum, pageSize);
        }
        Map<String, Object> res = new HashMap<>(2);
        int unreadConversationCount = 0;
        List<Map<String, Object>> conversationList = new ArrayList<>(pageInfo.getList().size());
        for (Message message : pageInfo.getList()) {
            Map<String, Object> map = new HashMap<>(3);
            MessageCountDTO messageCountDTO = messageService.countMessage(message.getConversationId(), user.getId());
            map.put("lastMessage", message);
            if (MessageTypeEnum.MESSAGE.getType().equals(messageType)) {
                map.put("messageCount", messageCountDTO.getMessageCount());
                map.put("unreadMessageCount", messageCountDTO.getUnreadMessageCount());
            }
            map.put("from", userService.findUserById(message.getFromId()));
            if (messageCountDTO.getUnreadMessageCount() > 0) {
                ++unreadConversationCount;
            }
            conversationList.add(map);
        }
        res.put("unreadMessageCount", unreadConversationCount);
        res.put("data", conversationList);

        return PageResult.getInstance(pageInfo.getTotal(), res);
    }

    @GetMapping("/messageList")
    @LoginRequired
    public PageResult getMessageList(@RequestParam String conversationId, @RequestParam Integer pageNum,
                                     @RequestParam Integer pageSize) {
        String currentUserId = redisUtil.getValueFromString(PREFIX_USER_ID, CookieUtil.getValue(request, MAP_KEY_TOKEN));
        User user = commonService.getUserByUserId(currentUserId);
        PageInfo<Message> pageInfo = messageService.getMessageList(conversationId, pageNum, pageSize, user.getId());
        List<Map<String, Object>> messageList = new ArrayList<>(pageInfo.getList().size());
        List<Integer> ids = new ArrayList<>(16);
        for (Message message : pageInfo.getList()) {
            Map<String, Object> map = new HashMap<>(2);
            map.put("message", message);
            map.put("from", userService.findUserById(message.getFromId()));
            messageList.add(map);
            // 未读的消息
            if (message.getToId() == user.getId() && message.getStatus() == MessageStatusEnum.UNREAD.getStatus()) {
                ids.add(message.getId());
            }
        }
        if (!ids.isEmpty()) {
            // 标记已读
            messageService.updateMessageStatus(ids, MessageStatusEnum.READ.getStatus(), user.getId());
        }
        return PageResult.getInstance(pageInfo.getTotal(), messageList);
    }

    @PostMapping("/reply")
    @LoginRequired
    public ResultDTO saveMessage(@RequestBody Message message) {
        String currentUserId = redisUtil.getValueFromString(PREFIX_USER_ID, CookieUtil.getValue(request, MAP_KEY_TOKEN));
        User user = commonService.getUserByUserId(currentUserId);
        String conversationId = message.getConversationId();
        // 新增
        if (StringUtils.isBlank(conversationId)) {
            User to = userService.findUserById(message.getToId());
            if (to == null) {
                throw new BusinessException(ResponseCodeEnum.CLIENT_ERROR.getCode(), "参数错误!");
            }
            conversationId = user.getId() + "_" + message.getToId();
            message.setConversationId(conversationId);
        } else { // 回复
            int count = messageService.countMessage(conversationId, user.getId()).getMessageCount();
            if (count == 0) {
                throw new BusinessException(ResponseCodeEnum.CLIENT_ERROR.getCode(), "参数错误!");
            }
            message.setToId(messageService.getToId(conversationId, user.getId()));
        }
        message.setCreateTime(new Date());
        message.setFromId(user.getId());
        // 这条消息对于接收者来说未读，对于发送者来说已读
        message.setStatus(MessageStatusEnum.UNREAD.getStatus());
        messageService.addMessage(message);
        return ResultDTO.builder().code(ResponseCodeEnum.SUCCESS.getCode()).build();
    }

    @PutMapping("/status/{messageId}/{status}")
    @LoginRequired
    public ResultDTO updateStatus(@PathVariable Integer messageId, @PathVariable Integer status) {
        String currentUserId = redisUtil.getValueFromString(PREFIX_USER_ID, CookieUtil.getValue(request, MAP_KEY_TOKEN));
        User user = commonService.getUserByUserId(currentUserId);
        Message message = messageService.getMessage(messageId, user.getId());
        if (message == null || status < MessageStatusEnum.UNREAD.getStatus() || status > MessageStatusEnum.DELETE.getStatus()) {
            throw new BusinessException(ResponseCodeEnum.CLIENT_ERROR.getCode(), "参数错误!");
        }
        List<Integer> ids = new ArrayList<>(1);
        ids.add(messageId);
        messageService.updateMessageStatus(ids, status, user.getId());
        return ResultDTO.builder().code(ResponseCodeEnum.SUCCESS.getCode()).build();
    }

    @DeleteMapping("/conversation/{id}")
    @LoginRequired
    public ResultDTO deleteConversation(@PathVariable String id) {
        String currentUserId = redisUtil.getValueFromString(PREFIX_USER_ID, CookieUtil.getValue(request, MAP_KEY_TOKEN));
        User user = commonService.getUserByUserId(currentUserId);
        messageService.deleteConverstion(id, user.getId());
        return ResultDTO.builder().code(ResponseCodeEnum.SUCCESS.getCode()).build();
    }
}
